#include <iostream>
#include <vector>
#include <functional>
#include <cassert>
#include <ctime>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MakeSeed() srand((unsigned long)time(nullptr) ^ getpid() ^ 0x171237 ^ rand() % 1234)

const int processnum = 5;
typedef std::function<void()> func_t;

void downloadTask()
{
    std::cout << getpid() << " 正在执行下载任务" << std::endl;
    sleep(1);
}

void IOTask()
{
    std::cout << getpid() << " 正在执行IO任务" << std::endl;
    sleep(1);
}

void fflushTask()
{
    std::cout << getpid() << " 正在执行刷新任务" << std::endl;
    sleep(1);
}

void loadTaskFunc(std::vector<func_t> &funcmap)
{
    funcmap.push_back(downloadTask);
    funcmap.push_back(IOTask);
    funcmap.push_back(fflushTask);
}

class subEp
{
public:
    subEp(const pid_t &subId, const int writeFd)
        : _subId(subId), _writeFd(writeFd)
    {
        char namebuffer[1024];
        snprintf(namebuffer, sizeof namebuffer, "process-%d[pid(%d) - fd(%d)]", _num++, _subId, _writeFd);
        _name = namebuffer;
    }

public:
    static int _num;
    std::string _name;
    pid_t _subId;
    int _writeFd;
};
int subEp::_num = 0;

int recvTask(int fd)
{
    int code = 0;
    ssize_t s = read(fd, &code, sizeof(code));
    if (s == 4)
        return code;
    else if (s <= 0)
        return -1;
    else
        return 0;
}

void sendTask(const subEp &process, int taskNum)
{
    std::cout << "send task num:" << taskNum << "send to ->" << process._name << std::endl;
    int n = write(process._writeFd, &taskNum, sizeof(taskNum));
    assert(n == 4);
    (void)n;
}

void createSubProcess(std::vector<subEp> &subs, std::vector<func_t> &funcmap)
{
    std::vector<int> deleteFd;
    for (int i = 0; i < processnum; i++)
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void)n;
        // 父进程打开的文件，是会被子进程共享的

        pid_t id = fork();
        if (id == 0)
        {
            close(fds[1]);
            while (true)
            {
                for (int i = 0; i < deleteFd.size(); i++)
                    close(deleteFd[i]);
                // 1. 获取命令码，如果没有发送，我们子进程应该阻塞
                int commandCode = recvTask(fds[0]);
                // 2. 完成任务
                if (commandCode >= 0 && commandCode < funcmap.size())
                    funcmap[commandCode]();
                else if (commandCode == -1)
                    break;
            }
            exit(0);
        }
        close(fds[0]);
        subs.push_back(subEp(id, fds[1]));
        deleteFd.push_back(fds[1]);
    }
}

void loadBlanceContrl(std::vector<subEp> &subs, std::vector<func_t> &funcmap, int count)
{
    int processnum = subs.size();
    int tasknum = funcmap.size();
    bool forever = (count == 0) ? true : false;

    while (true)
    {
        // 1. 选择一个子进程 --> std::vector<subEp> -> index - 随机数
        int subIdx = rand() % processnum;
        // 2. 选择一个任务 --> std::vector<func_t> -> index
        int taskIdx = rand() % tasknum;
        // 3. 任务发送给选择的进程
        sendTask(subs[subIdx], taskIdx);
        sleep(1);
        if (!forever && count > 0)
        {
            count--;
            if (count == 0)
                break;
        }
    }

    // write quit -> read 0
    for (int i = 0; i < processnum; i++)
        close(subs[i]._writeFd);
}

void waitProcess(std::vector<subEp> &subs)
{
    int processnum = subs.size();
    for (int i = 0; i < processnum; i++)
    {
        waitpid(subs[i]._subId, nullptr, 0);
        std::cout << "wait sub process success" << subs[i]._subId << std::endl;
    }
}

int main()
{
    MakeSeed();
    // 1. 建立子进程并建立和子进程通信的信道
    // 1.1 加载方法表
    std::vector<func_t> funcMap;
    loadTaskFunc(funcMap);
    // 1.2 创建子进程，并且维护好父子通信信道
    std::vector<subEp> subs;
    createSubProcess(subs, funcMap);

    // 2. 走到这里就是父进程, 控制子进程，负载均衡的向子进程发送命令码
    int taskCnt = 3; // 0: 永远进行
    loadBlanceContrl(subs, funcMap, taskCnt);

    // 3. 回收子进程信息
    waitProcess(subs);
    return 0;
}